<?php
/**
 * Created by sublime 3.
 * Auth: Inhere
 * Date: 14-9-28
 * Time: 10:35
 * Uesd: 主要功能是 hi
 */
namespace ulue\core\abstracts;

use ulue\core\TheSystemException;

abstract class AbstractCore
{
    public function __construct($config = [])
    {
        if ( !empty($config) ) {
            \Ulue::loadAttrs($this, (array)$config);
        }

        $this->init();
    }

    protected function init()
    {}

    /**
     * @todo  unused
     * @param  string  $method
     * @return boolean
     */
    protected function isAllowCall($method)
    {
        $filters = $this->filters();

        if (!$filters) {
            return true;
        }

        //阻止 ... '*' == 全部
        if (isset($filters['deny']) && ($denys=$filters['deny']) ) {
            if ($denys === '*') {
                return false;
            }

            if ( in_array($method, $denys) ) {
                return false;
            }
        }

        //允许 ...
        if (isset($filters['allow']) && ($allows = $filters['allow']) ) {
            if ($allows === '*') {
                return true;
            }

            if ( !in_array($method, $allows) ) {
                return false;
            }
        }

        # [method1,method2,...] a no key array, == $filters['allow']
        return in_array($method, (array)$filters);
    }

    /**
     * @todo  unused
     * @return []
     */
    protected function filters()
    {
        /*
        return [
          'deny'  => 'method1,method2, ...',
          'allow' => 'method1,method2, ...',
        ]
         */
        return [];

    }

    /**
     * propertys init, loadAttrs()
     * @param  array   $config
     * @param  boolean $reportError
     * @return void
     */
    protected function propertys(array $config=[])
    {
        \Ulue::loadAttrs($this, $config);
    }

    /**
     * get called class full name
     * @return string
     */
    final static public function fullName()
    {
        return get_called_class();
    }

    /**
     * get called class namesapce
     * @return string
     */
    final static public function spaceName($fullName=null)
    {
        $fullName = $fullName ? : self::fullName();

        return strpos($fullName, '\\') ? dirname($fullName) : null;
    }

    /**
     * get called class name
     * @return string
     */
    final static public function className($fullName=null)
    {
        $fullName = $fullName ? : self::fullName();

        return basename( $fullName );
    }

    /**
     * @reference yii2 yii\base\Object::__set()
     * @param $name
     * @param $value
     * @throws TheSystemException
     * @internal param $ [type] $name
     * @internal param $ [type] $value
     */
    public function __set($name,$value)
    {
        $method = 'set'.ucfirst( $name );

        if ( method_exists($this, $method) ) {
            $this->$method($value);
        } else if ( method_exists($this, 'get'.ucfirst( $name )) ) {
            throw new TheSystemException("Setting a Read-only property! ".get_class($this)."::{$name}", 'set');
        } else {
            throw new TheSystemException("Setting a Unknown property! ".get_class($this)."::{$name}", 'set');
        }
    }

    /**
     * @reference yii2 yii\base\Object::__set()
     * @param $name
     * @throws TheSystemException
     * @return mixed
     */
    public function __get($name)
    {
        $method = 'get'.ucfirst( $name );

        if (method_exists($this, $method)) {
            return $this->$method();
        }

        if (method_exists($this, 'set'.ucfirst( $name ))) {
            throw new TheSystemException("Getting a Write-only property! ".get_class($this)."::{$name}", 'get');
        }

        throw new TheSystemException("Getting a Unknown property! ".get_class($this)."::{$name}", 'get');
    }

    public function __isset($name)
    {
        $getter = 'get'.ucfirst( $name );

        if (method_exists($this, $getter)) {
            return $this->$getter() !== null;
        }

        return false;
    }

    public function __unset($name)
    {
        $setter = 'set'.ucfirst( $name );

        if (method_exists($this, $setter)) {
            $this->$setter(null);
            return;
        }

        throw new \DNotFoundException('Unsetting an unknown or read-only property: ' . get_class($this) . '::' . $name);
    }

    /**
     * @param $method
     * @param $args
     * @throws \DUnknownCalledException
     * @return mixed
     */
    public function __call($method,$args)
    {
        if (method_exists($this, $method) && $this->isAllowCall($method) ) {

            return call_user_func_array( array($this, $method), (array) $args);
        }

        throw new \DUnknownCalledException("Called a Unknown method! ".get_class($this)."::{$method}()");
    }

}